<!--
 * @Author: xuwejie 1529315455@qq.com
 * @Date: 2023-08-28 14:39:14
 * @LastEditors: raoyonggang 11886335+ryg321@user.noreply.gitee.com
 * @LastEditTime: 2024-04-12 09:44:18
 * @FilePath: \v9\src\views\bigData\demo.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
  <div :style="immediately ? { display: 'none' } : {}">
    <div class="top">
      <el-page-header @back="goBack" content="详情页面"> </el-page-header>
    </div>
    <div id="luckysheet"></div>
    <div class="btn" @click="handleExportExcel">
      <svg-icon icon-class="import"></svg-icon>
      <span>导出</span>
    </div>
  </div>
</template>

<script>
// import { utils, write } from "xlsx";
import LocalForage from "localforage";
const ExcelJS = require("exceljs");
import FileSaver from "file-saver";
export default {
  name: "",
  data() {
    return {
      list: [],
      time: null,
      classification: [],
      immediately: false,

      // 设置excel表格从第6行开始渲染（最终渲染为rowRendeIndex+1）
      rowRendeIndex: 5,
      // 设置excel表格的表头数据初始格式(还需追加分组数据)
      table_top: [
        {
          name: "商品规格id",
          k: 0,
        },
        {
          name: "一级/二级分类",
          k: 1,
        },
        {
          name: "商品名称【规格】",
          k: 2,
        },
      ],
    };
  },

  methods: {},
  mounted() {
    LocalForage.getItem("pricingTemplate").then((res) => {
      this.list = res.list;
      this.time = res.time;
      this.classification = res.classification;
      this.immediately = res.immediately;
      this.init(res.immediately);
    });
  },
  methods: {
    init(state) {
      // 设置表头格式数据
      let data = this.configurationTable();
      const options = {
        container: "luckysheet", // 设定DOM容器的id
        title: "Luckysheet Demo", // 设定表格名称
        lang: "zh", // 设定表格语言
        data: data, // 设定表格数据
      };
      window.luckysheet.create(options);
      if (state) {
        this.handleExportExcel();
      }
    },

    // 设置表格名称、备注等数据
    defaultTable(celldata) {
      // 表格名称
      let data = [
        {
          r: 0,
          c: 0,
          v: {
            v: `${this.time}_批量核价`,
            fc: "#000000",
            ht: 0, //水平居中
            fs: 20,
            bl: 1, //字体加粗
          },
        },
      ];
      let remarks = [
        {
          r: 1,
          c: 0,
          v: {
            v: `温馨提示:修改数据的格式:202.32-209.882,数据说明:202.32(修改前价格)-209.88(修改后价格);注：中间用“-”符号隔开。`,
            fc: "#39aeff",
            ht: 1,
            fs: 18,
            bl: 1, //字体加粗
          },
        },
        {
          r: 2,
          c: 0,
          v: {
            v: `注意：标题栏，分组名称，商品规格ID等数据请勿修改，否则引起导入数据错误或数据导入不成功！`,
            fc: "#FF0000",
            ht: 1,
            fs: 18,
            bl: 1, //字体加粗
          },
        },
      ];
      let borderDate = [];
      let borderRemarks = [];
      let column = celldata.length < 10 ? 10 : celldata.length;
      for (let i = 0; i < column; i++) {
        borderDate.push({
          rangeType: "cell",
          value: {
            row_index: 0,
            col_index: i,
            l: {
              style: 1,
              color: "rgb(0, 0, 0)",
            },
            r: {
              style: 1,
              color: "rgb(0, 0, 0)",
            },
            t: {
              style: 1,
              color: "rgb(0, 0, 0)",
            },
            b: {
              style: 1,
              color: "rgb(0, 0, 0)",
            },
          },
        });
        borderRemarks.push({
          rangeType: "cell",
          value: {
            row_index: 2,
            col_index: i,
            l: {
              style: 1,
              color: "rgb(0, 0, 0)",
            },
            r: {
              style: 1,
              color: "rgb(0, 0, 0)",
            },
            t: {
              style: 1,
              color: "rgb(0, 0, 0)",
            },
            b: {
              style: 1,
              color: "rgb(0, 0, 0)",
            },
          },
        });
      }
      borderRemarks.push({
        rangeType: "cell",
        value: {
          row_index: 1,
          col_index: 9,
          l: {
            style: 1,
            color: "rgb(0, 0, 0)",
          },
          r: {
            style: 1,
            color: "rgb(0, 0, 0)",
          },
          t: {
            style: 1,
            color: "rgb(0, 0, 0)",
          },
          b: {
            style: 1,
            color: "rgb(0, 0, 0)",
          },
        },
      });
      let newList = [...data, ...remarks];
      let newBorder = [...borderDate, ...borderRemarks];
      return { defaultTable: newList, defaultBorder: newBorder };
    },
    // 配置工作表头格式
    configurationTable() {
      let that = this;
      // 获取分组列表数据格式
      let list = this._.cloneDeep(this.list);
      // 深克隆excel表头初始数据
      let table_top = this._.cloneDeep(this.table_top);
      // 获取其余表头数据
      let group = this._.cloneDeep(list[0].group);
      // 循环便利获取完整表头数据
      let { celldata, borderInfo } = this.getAllTableTop(group, table_top);
      // 设置最小列数
      let column = table_top.length < 10 ? 10 : table_top.length;
      // 设置最小行数
      let row = list.length < 10 ? 20 : list.length + 10;
      // 设置表格名称、备注等数据
      let { defaultTable, defaultBorder } = this.defaultTable(celldata);
      // 设置表格商品数据
      let { shopName, shopBorder } = this.getAllShopName(list);
      // 获取完整的商品对应的价格数据
      let { priceList, priceBorder } = this.getAllShopPrice(list);

      // ! 将表头、表格名称、备注、数据等内容合并进行数据渲染
      let newCelldata = [
        ...defaultTable,
        ...celldata,
        ...shopName,
        ...priceList,
      ];
      let newBorderInfo = [
        ...defaultBorder,
        ...borderInfo,
        ...shopBorder,
        ...priceBorder,
      ];
      let data = [
        {
          name: "2024-01-25",
          color: "#ff0000",
          index: 0,
          status: 1,
          hide: 0,
          row: row,
          column: column,
          defaultRowHeight: 40,
          defaultColWidth: 170,
          celldata: newCelldata,
          config: {
            merge: {
              "0_0": {
                r: 0,
                c: 0,
                rs: 1,
                cs: column,
              },
              "1_0": {
                r: 1,
                c: 0,
                rs: 1,
                cs: column,
              },
              "2_0": {
                r: 2,
                c: 0,
                rs: 1,
                cs: column,
              },
            },
            borderInfo: newBorderInfo,
            // 设置特定的列宽度
            columnlen: {
              0: 100,
              1: 160,
              2: 180,
            },
          },
          frozen: {
            type: "rangeBoth",
            range: { row_focus: 5, column_focus: 2 },
          },
        },
      ];
      return data;
    },
    // 获取完整表头数据
    getAllTableTop(group, table_top) {
      let that = this;
      group.forEach((i, k) => {
        table_top.push({
          name: `${i.title}-${i.group_id}`,
        });
      });
      let celldata = table_top.map((item, index) => {
        return {
          r: that.rowRendeIndex,
          c: index,
          v: {
            v: item.name,
            fc: item.fc || "#000000",
            ht: item.ht || 0, //水平居中
            fs: item.fs || 16, //字体大小
            bl: item.bl || 1, //字体加粗
          },
        };
      });
      let borderInfo = table_top.map((item, index) => {
        return {
          rangeType: "cell",
          value: {
            row_index: that.rowRendeIndex,
            col_index: index,
            l: {
              style: 1,
              color: "rgb(0, 0, 0)",
            },
            r: {
              style: 1,
              color: "rgb(0, 0, 0)",
            },
            t: {
              style: 1,
              color: "rgb(0, 0, 0)",
            },
            b: {
              style: 1,
              color: "rgb(0, 0, 0)",
            },
          },
        };
      });
      return { celldata, borderInfo };
    },
    // 获取所有商品名称格式数据
    getAllShopName(list) {
      let that = this;
      let newList = [];
      let newBorder = [];
      // 设置商品名称
      list.forEach((item, index) => {
        that.table_top.forEach((i, j) => {
          let v = null;
          if (j == 0) v = `${item.id}`;
          else if (j == 1) {
            // 一级分类id
            let pid = item.goods.pid;
            // 二级分类id
            let id = item.goods.category_id;
            // 反解析分类内容
            let categoryIndex = that.classification.findIndex(
              (a) => a.id == pid
            );
            if (categoryIndex != -1) {
              let titleA = "";
              let objA = that.classification[categoryIndex];
              if (typeof objA == "undefined") {
                titleA = "";
              } else {
                titleA = objA.title;
              }
              // 一级分类名称
              let classAName =
                categoryIndex == "-1" || categoryIndex == "0" ? "" : titleA;
              // 二级分类名称
              let titleB = "";
              if (categoryIndex == 0) {
                v = `${classAName}/`;
              } else {
                let objB = that.classification[categoryIndex].selfNext.find(
                  (b) => b.id == id
                );
                if (typeof objB == "undefined") {
                  titleB = "";
                } else {
                  titleB = objB.title;
                }
                let classBName =
                  categoryIndex == "-1" || categoryIndex == "0" ? "" : titleB;
                v = `${classAName}/${classBName}`;
              }
            } else {
              v = ``;
            }
          } else if (j == 2) {
            let spu_name_title = item.spu_name ? item.spu_name.title : "";
            v = `${item.goods.name}【${spu_name_title}】`;
          }
          newList.push({
            r: that.rowRendeIndex + 1 + index,
            c: j,
            v: {
              v: v,
              fc: "#000000",
              ht: 0, //水平居中
              fs: 16, //字体大小
              bl: 0, //字体加粗
            },
          });

          newBorder.push({
            rangeType: "cell",
            value: {
              row_index: that.rowRendeIndex + 1 + index,
              col_index: j,
              l: {
                style: 1,
                color: "rgb(0, 0, 0)",
              },
              r: {
                style: 1,
                color: "rgb(0, 0, 0)",
              },
              t: {
                style: 1,
                color: "rgb(0, 0, 0)",
              },
              b: {
                style: 1,
                color: "rgb(0, 0, 0)",
              },
            },
          });
        });
      });

      return { shopName: newList, shopBorder: newBorder };
    },
    // 获取完整的商品对应的价格数据
    getAllShopPrice(list) {
      let that = this;
      let newList = [];
      let newBorder = [];
      list.map((item, index) => {
        item.group.forEach((i, j) => {
          let data = {
            r: that.rowRendeIndex + 1 + index,
            c: j + 3,
            v: {
              v: i.real_price,
              fc: "#000000",
              ht: 0, //水平居中
              fs: 16, //字体大小
              bl: 0, //字体加粗
            },
          };
          newList.push(data);
          newBorder.push({
            rangeType: "cell",
            value: {
              row_index: that.rowRendeIndex + 1 + index,
              col_index: j + 3,
              l: {
                style: 1,
                color: "rgb(0, 0, 0)",
              },
              r: {
                style: 1,
                color: "rgb(0, 0, 0)",
              },
              t: {
                style: 1,
                color: "rgb(0, 0, 0)",
              },
              b: {
                style: 1,
                color: "rgb(0, 0, 0)",
              },
            },
          });
        });
      });
      return { priceList: newList, priceBorder: newBorder };
    },
    handleExportExcel() {
      let tableArr = window.luckysheet.getLuckysheetfile();
      this.exportExcel(tableArr);
    },
    async exportExcel(tableArr) {
      // 参数为luckysheet.getluckysheetfile()获取的对象
      // 1.创建工作簿，可以为工作簿添加属性
      const workbook = new ExcelJS.Workbook();
      // 2.创建表格，第二个参数可以配置创建什么样的工作表
      tableArr.every((table) => {
        if (table.data.length === 0) return true;
        const worksheet = workbook.addWorksheet(table.name);
        // 3.设置单元格合并,设置单元格边框,设置单元格样式,设置值
        this.setStyleAndValue(table.data, worksheet);
        this.setMerge(table.config.merge, worksheet);
        this.setBorder(table.config.borderInfo, worksheet);
        this.setWidth(table.config, worksheet);
        let row = this.list.length < 10 ? 20 : this.list.length + 10;
        for (let i = 1; i <= row; i++) {
          worksheet.getRow(i).height = 30;
        }
        worksheet.views = [
          {
            state: "frozen",
            xSplit: 3, // 冻结前四列
            ySplit: 6, // 冻结前六行
          },
        ];

        return true;
      });
      // 4.写入 buffer
      const buffer = await workbook.xlsx.writeBuffer();
      //调用文件保存插件
      FileSaver.saveAs(
        new Blob([buffer], { type: "application/octet-stream" }),
        "批量核价" + ".xlsx"
      );
      return buffer;
    },

    setMerge(luckyMerge = {}, worksheet) {
      const mergearr = Object.values(luckyMerge);
      mergearr.forEach((elem) => {
        // elem格式：{r: 0, c: 0, rs: 1, cs: 2}
        // 按开始行，开始列，结束行，结束列合并（相当于 K10:M12）
        worksheet.mergeCells(
          elem.r + 1,
          elem.c + 1,
          elem.r + elem.rs,
          elem.c + elem.cs
        );
      });
    },
    setWidth(luckyColumn = {}, worksheet) {
      let group = this.list[0].group;
      let columns = [{ width: 23 }, { width: 25 }, { width: 25 }];
      group.forEach(() => {
        columns.push({ width: 30 });
      });
      worksheet.columns = columns;
    },

    setBorder(luckyBorderInfo, worksheet) {
      if (!Array.isArray(luckyBorderInfo)) return;
      luckyBorderInfo.forEach(function (elem) {
        var val = elem.value;
        let border = {};
        const luckyToExcel = {
          type: {
            "border-all": "all",
            "border-top": "top",
            "border-right": "right",
            "border-bottom": "bottom",
            "border-left": "left",
          },
          style: {
            0: "none",
            1: "thin",
            2: "hair",
            3: "dotted",
            4: "dashDot", // 'Dashed',
            5: "dashDot",
            6: "dashDotDot",
            7: "double",
            8: "medium",
            9: "mediumDashed",
            10: "mediumDashDot",
            11: "mediumDashDotDot",
            12: "slantDashDot",
            13: "thick",
          },
        };

        if (val) {
          if (val.t != undefined) {
            border["top"] = {
              style: luckyToExcel.style[val.t.style],
              color: val.t.color,
            };
          }
          if (val.r != undefined) {
            border["right"] = {
              style: luckyToExcel.style[val.r.style],
              color: val.r.color,
            };
          }
          if (val.b != undefined) {
            border["bottom"] = {
              style: luckyToExcel.style[val.b.style],
              color: val.b.color,
            };
          }
          if (val.l != undefined) {
            border["left"] = {
              style: luckyToExcel.style[val.l.style],
              color: val.l.color,
            };
          }
          worksheet.getCell(val.row_index + 1, val.col_index + 1).border =
            border;
        }
      });
    },
    setStyleAndValue(cellArr, worksheet) {
      if (!Array.isArray(cellArr)) return;
      cellArr.forEach((row, rowid) => {
        row.every((cell, columnid) => {
          if (!cell) return true;
          let fill = this.fillConvert(cell.bg);
          let font = this.fontConvert(
            cell.ff,
            cell.fc,
            cell.bl,
            cell.it,
            cell.fs,
            cell.cl,
            cell.ul
          );
          let alignment = this.alignmentConvert(
            cell.vt,
            cell.ht,
            cell.tb,
            cell.tr
          );
          let value;
          if (cell.f) {
            value = { formula: cell.f, result: cell.v };
          } else {
            value = cell.v;
          }
          let target = worksheet.getCell(rowid + 1, columnid + 1);
          target.fill = fill;
          target.font = font;
          target.alignment = alignment;
          target.value = value;
          return true;
        });
      });
    },

    fillConvert(bg) {
      if (!bg) {
        return {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "#ffffff".replace("#", "") },
        };
      }
      let fill = {
        type: "pattern",
        pattern: "solid",
        fgColor: { argb: this.colorHex(bg).replace("#", "") },
      };
      return fill;
    },
    //将rgb()转成16进制
    colorHex(color) {
      // RGB颜色值的正则
      var reg = /^(rgb|RGB)/;
      if (reg.test(color)) {
        var strHex = "#";
        // 把RGB的3个数值变成数组
        var colorArr = color.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(",");
        // 转成16进制
        for (var i = 0; i < colorArr.length; i++) {
          var hex = Number(colorArr[i]).toString(16);
          if (hex === "0") {
            hex += hex;
          }
          strHex += hex;
        }
        return strHex;
      } else {
        return String(color);
      }
    },
    fontConvert(
      ff = 0,
      fc = "#000000",
      bl = 0,
      it = 0,
      fs = 10,
      cl = 0,
      ul = 0
    ) {
      // luckysheet：ff(样式), fc(颜色), bl(粗体), it(斜体), fs(大小), cl(删除线), ul(下划线)
      const luckyToExcel = {
        0: "微软雅黑",
        1: "宋体（Song）",
        2: "黑体（ST Heiti）",
        3: "楷体（ST Kaiti）",
        4: "仿宋（ST FangSong）",
        5: "新宋体（ST Song）",
        6: "华文新魏",
        7: "华文行楷",
        8: "华文隶书",
        9: "Arial",
        10: "Times New Roman ",
        11: "Tahoma ",
        12: "Verdana",
        num2bl: function (num) {
          return num === 0 ? false : true;
        },
      };

      let font = {
        name: luckyToExcel[ff],
        family: 1,
        size: fs,
        color: { argb: fc.replace("#", "") },
        bold: luckyToExcel.num2bl(bl),
        italic: luckyToExcel.num2bl(it),
        underline: luckyToExcel.num2bl(ul),
        strike: luckyToExcel.num2bl(cl),
      };

      return font;
    },

    alignmentConvert(
      vt = "default",
      ht = "default",
      tb = "default",
      tr = "default"
    ) {
      // luckysheet:vt(垂直), ht(水平), tb(换行), tr(旋转)
      const luckyToExcel = {
        vertical: {
          0: "middle",
          1: "top",
          2: "bottom",
          default: "top",
        },
        horizontal: {
          0: "center",
          1: "left",
          2: "right",
          default: "left",
        },
        wrapText: {
          0: false,
          1: false,
          2: true,
          default: false,
        },
        textRotation: {
          0: 0,
          1: 45,
          2: -45,
          3: "vertical",
          4: 90,
          5: -90,
          default: 0,
        },
      };

      let alignment = {
        vertical: luckyToExcel.vertical[vt],
        horizontal: luckyToExcel.horizontal[ht],
        wrapText: luckyToExcel.wrapText[tb],
        textRotation: luckyToExcel.textRotation[tr],
      };
      return alignment;
    },

    borderConvert(borderType, style = 1, color = "#000") {
      // 对应luckysheet的config中borderinfo的的参数
      if (!borderType) {
        return {};
      }
      const luckyToExcel = {
        type: {
          "border-all": "all",
          "border-top": "top",
          "border-right": "right",
          "border-bottom": "bottom",
          "border-left": "left",
        },
        style: {
          0: "none",
          1: "thin",
          2: "hair",
          3: "dotted",
          4: "dashDot", // 'Dashed',
          5: "dashDot",
          6: "dashDotDot",
          7: "double",
          8: "medium",
          9: "mediumDashed",
          10: "mediumDashDot",
          11: "mediumDashDotDot",
          12: "slantDashDot",
          13: "thick",
        },
      };
      let template = {
        style: luckyToExcel.style[style],
        color: { argb: color.replace("#", "") },
      };
      let border = {};
      if (luckyToExcel.type[borderType] === "all") {
        border["top"] = template;
        border["right"] = template;
        border["bottom"] = template;
        border["left"] = template;
      } else {
        border[luckyToExcel.type[borderType]] = template;
      }
      return border;
    },
    goBack() {
      // console.log("go back");
      this.$router.go(-1);
    },
  },
};
</script>

<style lang="scss" scoped>
#luckysheet {
  height: 100vh !important;
}
/deep/.luckysheet {
  height: 100vh !important;
}

.top {
  height: 60px;
  width: 100%;
  background: #fff;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 99999;
}

.btn {
  position: absolute;
  right: 150px;
  bottom: 100px;
  z-index: 9999;
  width: 100px;
  height: 35px;
  line-height: 35px;
  border-radius: 4px;
  border: 1px solid #3685f9;
  display: flex;
  background: #fff;
  align-items: center;
  justify-content: space-evenly;
}
/deep/.el-page-header {
  line-height: 60px;
  padding-left: 20px;
  box-sizing: border-box;
}
</style>